#include <memory.h>

#include "mathutils.h"
#include "texgenprimitives.h"
#include "texgen.h"

#ifdef EDITOR_MODE
#include <fstream>
#endif

using namespace Texgen;

Generator::Generator() {
  numactions=0;
#ifdef EDITOR_MODE
  totalactions=0;
#endif
  for (int i = 0; i < 4; i++) 
    layers[i] = new int32[TSIZE * TSIZE];
  reset();
}
#ifdef EDITOR_MODE
Generator::~Generator() {
  for (int i=0; i<4; i++) {
    delete [] layers[i];
  }
}
#endif

void Generator::execute(Action &action) {
  mask = 0;
  int m = action.mask;
  if (m & 1) mask |= 0xff;
  if (m & 2) mask |= 0xff00;
  if (m & 4) mask |= 0xff0000;
  if (m & 8) mask |= 0xff000000;
  op = action.op;
  SetSeed(action.param1); //all random dep. functions have the seed in param 1, so we can safely use this without disturbing anything
  int32 *layer=layers[action.layer];
  switch (action.type) {
  case 0: //noise
    mononoise(action.param2,action.param3);
    break;
  case 1:
    fractalplasma(action.param2, action.param3);
    break;
  case 2:
    cells(action.param2, action.param3, action.param4);
    break;
  case 3:
    sines(action.param1,action.param2);
    break;
  case 4:
    chess(action.param1,action.param2);
    break;
  case 5:
    circular(action.param1,action.param2,action.param3);
    break;
  case 6:
    clear((action.param1<<24)|(action.param2<<16)|(action.param3<<8)|(action.param4));
    break;
  case 7:
    tilepic(layer,action.nameparam,action.param1,action.param2);
    break;
  case 8:
    drawpic(layer,action.nameparam,action.param1,action.param2,action.param3,action.param4);
    break;
  case 9:
    //radialsines(layer,action.param1,action.param2);
#ifdef STUDIO
    MessageBox(0,"Radial sines removed: use sines and polar circle instead",0,0);
#endif
    break;
  case 10:
    subplasma(action.param2,action.param3);
    break;
  case 11:
    copyimage(layers[action.data1]);
    break;
  case 12:
    alphablend(layer,layers[action.data1],action.param1);
    break;
  case 13:
    alphablenddatalayer(layer,layers[action.data1],layers[action.data2]);
    break;
  case 14:
    offset(layer,action.param1,action.param2);
    break;
  case 15:
    emboss(layer,action.param1);
    break;
  case 16:
    sinecolor(layer,action.param1);
    break;
  case 17:
    sinedist(layer,action.param1,action.param2,action.param3,action.param4);
    break;
  case 18:
    shade(layer,layers[action.data1]);
    break;
  case 19:
    invert(layer);
    break;
  case 20:
    blur(layer,action.param1);
    break;
  case 21:
    hsv_adjust(layer,action.param1,action.param2);
    break;
  case 22:
    rotate90(layer);
    break;
  case 23:
    rgb2hsv(layer,action.param1,action.param2);
    break;
  case 24:
    contrast(layer,action.param1);
    break;
  case 25:
    tex_max(layer,layers[action.data1]);
    break;
  case 26:
    emboss2(layer,action.param1);
    break;
  case 27:
    polar(layer,action.param1,action.param2);
    break;
  case 28:
    mapdistort(layer, layers[action.data1], layers[action.data2], action.param1, action.param2, action.param3);
    break;
  case 29:
    lightrays(action.param2);
    break;
  case 30:
    blue2all(layer);
    break;
  case 31:
    tonormalmap(layers[action.data1], action.param1);
    break;
  }
  copytemp(layer);
}

void Generator::execute_all() 
{
  reset();
  for (int i=0; i<numactions; i++) {
    execute(actions[i]);
  }
}

void Generator::reset() {
  mask=0xffffffff;
  op='=';
  for (int i=0; i<4; i++) {
    clear(0xff000000); //100% alpha, black
    copytemp(layers[i]);
  }
}

void Generator::readfrommem(char8 *mem) {
  numactions = *mem++;
  memcpy(actions,mem,numactions*sizeof(Action));
  reset();
  execute_all();
}


#ifdef EDITOR_MODE
void Generator::load(const char *filename, int32 &ID) {
	std::ifstream f;
  f.open(filename,std::ios::in | std::ios::binary);
  char n;
  f.read(&n,1);

  int len=n*sizeof(Action)+1;
  f.seekg(0,std::ios::beg);

  char *temp=new char[len];
  f.read(temp, len);
  f.read((char *)&ID,sizeof(int32));
  f.close();
  readfrommem((char8*)temp);
  totalactions=numactions;
  delete [] temp;
}



void Generator::save(const char *filename, int32 ID) {
  std::ofstream f;
  f.open(filename,std::ios::out | std::ios::binary);
  char numac=numactions;
  f.write(&numac,1);
  f.write((char *)actions,sizeof(Action)*numactions);
  f.write((char *)&ID,sizeof(int32));
  f.close();
}

void Generator::writetomem(char8 *mem) {
  *mem++=numactions;
  memcpy(mem,actions,sizeof(Action)*numactions);
}

int Generator::sizeoftex()
{
  return 1 + numactions*sizeof(Action);
}

void Generator::tolist(CListBox &list) {
  list.ResetContent();
  for (int i=0; i<totalactions; i++) {
    CString str=((i<numactions) ? CString("") : CString("* ")) + actioninfo[actions[i].type].name + " (" + CString((char)actions[i].op) + ") ";
    if (actions[i].type==7 || actions[i].type==8)
      str += ""; //ID2STRING(actions[i].nameparam);
    list.AddString(str);
  }
}

void Generator::add(Action &action) {
  actions[numactions++]=action;
  if (numactions>totalactions) totalactions=numactions;
}
void Generator::add_and_execute(Action &action) {
  add(action);
  execute(action);
}

void Generator::del(int i) {
  if (numactions==0) {
    MessageBox(0, "Would you like -1 filters?\n(hello Aardbei! :)", "Jerk!",0);
    return;
  }

  //TODO: add code
}
void Generator::undo() {
  if (numactions<=0) {
    //MessageBox(0, "Would you like -1 filters?", "Hey!",0);
    return;
  }
  numactions--;
  execute_all();
}
void Generator::redo() {
  if (numactions>=totalactions) {
    MessageBox(0, "What? Redo an operation not done? No way!", "Hey!",0);
    return;
  }
  numactions++;
  execute(actions[numactions-1]);
}

void Generator::up(int i) {
  if (i<=0) return;

  //TODO: add code
}
void Generator::down(int i) {
  if (i>=numactions-1) return;

  //TODO: add code
}

ActionInfo actioninfo[32] = {
  { //0
    "Noise",
      0,
      0,
      3,
      "Rnd. Seed",
      "X Size (8)",
      "Y Size (8)",
      0,
      0
  },
  { //1
    "Fractal Plasma",
      0,
      0,
      2,
      "Rnd. Seed",
      "Turbulence",
      0,
      0,
      0
  },
  { //2
    "Cells",
      0,
      0,
      4,
      "Rnd. Seed",
      "Num of cells",
      "Strength",
      "Type (8)",
      0
  },
  { //3
    "Sinewaves",
      0,
      0,
      2,
      "X-sines",
      "Y-sines",
      0,
      0,
      0
  },
  { //4
    "Chess",
      0,
      0,
      2,
      "X Size (8)",
      "Y Size (8)",
      0,
      0,
      0
  },
  { //5
    "Circular (types 0-1)",
      0,
      0,
      3,
      "Param 1",
      "Param 2",
      "Type (8)",
      0,
      0
  },
  { //6
    "Clear",
      0,
      0,
      4,
      "Alpha",
      "Red",
      "Green",
      "Blue",
      0
  },
  { //7
    "Tile picture",
      0,
      0,
      2,
      "Magnify X (8)",
      "Magnify Y (8)",
      0,
      0,
      "Picture ID"
  },
  { //8
    "Draw picture at x,y",
      0,
      0,
      4,
      "Magnify X (8)",
      "Magnify Y (8)",
      "X",
      "Y",
      "Picture ID"
  },
  { //9
    "Radial Sines (NOWRAP)",
      0,
      0,
      2,
      "Num sines",
      "Offset",
      0,
      0,
      0
  },
  { //10
    "Subplasma",
      0,
      0,
      3,
      "Rnd. Seed",
      "X-Size (8)",
      "Y-Size (8)",
      0,
      0
  },
  { //11
    "Copy texture",
      1,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  { //12
    "Alphablend texture",
      1,
      0,
      1,
      "Alpha",
      0,
      0,
      0,
      0
  },
  { //13
    "Alphablend texture with data layer",
      1,
      1,
      1,
      0,
      0,
      0,
      0,
      0
  },
  { //14
    "Offset",
      0,
      0,
      2,
      "X offset",
      "Y offset",
      0,
      0,
      0
  },
  { //15
    "Emboss",
      0,
      0,
      1,
      "Strength",
      0,
      0,
      0,
      0
  },
  { //16
    "Sinecolor",
      0,
      0,
      1,
      "Num of sines",
      0,
      0,
      0,
      0
  },
  { //17
    "Sine Distort",
      0,
      0,
      4,
      "X-sines",
      "X-amount",
      "Y-sines",
      "Y-amount",
      0
  },
  { //18
    "Shade",
      1,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  { //19
    "Invert",
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  { //20
    "Blur",
      0,
      0,
      1,
      "Times (8)",
      0,
      0,
      0,
      0
  },
  { //21
    "Hue/Sat Adjust",
      0,
      0,
      2,
      "HueRotate",
      "SaturationScale",
      0,
      0,
      0
  },
  { //22
    "Rotate 90 degrees",
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  { //23
    "R,G,B to H,S,V",
      0,
      0,
      2,
      "HueRotate",
      "SaturationScale",
      0,
      0,
      0
  },
  { //24
    "Reduce contrast",
      0,
      0,
      1,
      "Reduction",
      0,
      0,
      0,
      0
  },
  { //25
    "Max",
      1,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  { //26
    "Emboss 2",
      0,
      0,
      1,
      "Strength",
      0,
      0,
      0,
      0
  },
  { //27
    "Polar Circle",
      0,
      0,
      2,
      "Magnify",
      "Revolutions",
      0,
      0,
      0
  },
  { //28
    "Mapdistort (data1,2=X,Y), uses blue as coord",
      1,
      1,
      3,
      "X amplitude",
      "Y amplitude",
      "Offcompnst.",
      0,
      0
  },
  { //29
    "Light Rays",
      0,
      0,
      2,
      "Rnd. Seed",
      "Amount",
      0,
      0,
      0
  },
  {
    "Blue to all",
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
  },
  {
    "To normal map",
      1,
      0,
      1,
      "Height mul",
      0,
      0,
      0,
      0
  },
};

#endif

